﻿using System;
using System.Collections.Generic;

namespace CardsEngine.Poker.PokerTestKit
{
    public sealed class BasicMathProvider: IMathFunctionProvider
    {
        private struct Point
        {
            public int x;
            public int y;

            public Point(int _x, int _y)
            {
                x = _x;
                y = _y;
            }
        }

        private IDictionary<Point, int> nCrLookupTable;

        public BasicMathProvider()
            :base()
        {
            InitializeInstance();
        }

        public BasicMathProvider(IFactory factory)
            :base(factory)
        {
            InitializeInstance();
        }

        private void InitializeInstance()
        {
            nCrLookupTable = Factory.GetNewDictionary<Point, int>();
        }

        // This is an algorithm I found online.
        // No clue how it works.
        public uint ComputeHammingWeight32(UInt32 i)
        {
            i = i - ((i >> 1) & 0x55555555);
            i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
            return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
        }

        public int nCr(int n, int r)
        {
            Point p = new Point(n, r);

            if (!nCrLookupTable.ContainsKey(p))
            {
                int result;

                if (n == r)
                    result = 1;
                else if (r == 1)
                    result = n;
                else
                    result = nCr(n - 1, r) + nCr(n - 1, r - 1);

                nCrLookupTable[p] = result;
            }

            return nCrLookupTable[p];
        }

        /*
        // Implementation which does NOT support lookup table functionality
        public int nCr(int n, int r)
        {
           if (n == r) return 1;
           if (r == 1) return n;

           return nCr(n - 1, r) + nCr(n - 1, r - 1);
        }
        */
    }
}
